package com.handinfo.engine.net;

import java.io.*;

import javax.microedition.io.*;

import com.handinfo.engine.GameManager;
import com.handinfo.util.Tools;

/**
 * @author Xia Mingwei
 * @version 1.0
 */
public class TcpConnection extends BaseConnection
{

	private ReaderThread m_rthread; // 读线程
	private WriterThread m_wthread; // 写线程

	private boolean m_isClosing; // 连接是否关闭
	public static final int TRANSNUM = 10;

	public TcpConnection(String server, int port, ConnectionHandler recver)
	{
		m_handler = recver;
		setServiceInfo(server, port);
		m_alive = false;
	}

	/**
	 * @param server
	 * @param port
	 * @roseuid 431FC903035B
	 */
	public void setServiceInfo(String ip, int port)
	{
		m_server = ip;
		m_port = port;
		StringBuffer sname = new StringBuffer();
		sname.append("socket://");
		sname.append(m_server);
		sname.append(":");
		sname.append(m_port);
		m_url = sname.toString();
	}

	/**
	 * 打开一个连接，并当成一个线程启动
	 */
	public void open()
	{
		super.open();
		m_isClosing = false;
		// 打开连接		
		openSocket();
		m_rthread = new ReaderThread();
		m_wthread = new WriterThread();
		new Thread(this).start();
	}
    
	/**
	 * 关闭连接
	 */
	public void close()
	{
		m_isClosing = true;
		m_rthread = null;
		m_wthread = null;
		super.close();
	}

	/**
	 * 定时发送心跳包
	 */
	public void keepAlive()
	{
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		DataOutputStream dos = new DataOutputStream(baos);
		try {
			dos.writeLong(System.currentTimeMillis());
			sendMessage(BaseConnection.DEST_GATEWAY, 0,
					GameProtocol.CS_HEARTBEAT, baos.toByteArray());
			dos.close();
			dos = null;
			baos.close();
			baos = null;
		}
		catch (IOException ex) {
			Tools.debug(ex);
		}
	}
	
	/**
	 * 定时发送心跳包
	 */
	public void delaysTime()
	{
		int size = GameManager.s_delaysTimeNum;
		if( size < TRANSNUM){
			Tools.debugPrintln("TcpConnecttion delaysTime-----------="+size);
			return;
		}else{
			GameManager.s_delaysTimeNum = -1;
			Tools.debugPrintln("TcpConnecttion delaysTime>>>>>>>>>>>");
		}
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		DataOutputStream dos = new DataOutputStream(baos);
		try {
            
			for(int i=0;i<size;i++){
				dos.writeLong(GameManager.s_delaysTimes[i][0]);
				dos.writeLong(GameManager.s_delaysTimes[i][1]);
			}
			sendMessage(BaseConnection.DEST_GATEWAY, 0,
					GameProtocol.SC_DELAYSTIMES, baos.toByteArray());
			dos.close();
			dos = null;
			baos.close();
			baos = null;
		}
		catch (IOException ex) {
			Tools.debug(ex);
		}
	}
	
	

	/**
	 * 发送消息
	 * 
	 * @param destId
	 * @param type
	 * @param order
	 * @param body
	 * @return
	 */
	public boolean sendMessage(int destId, int type, int order, byte[] body)
	{
		byte[] pack = packageMessage(destId, type, order, body);
		// 把一个数据包放进发送队列，并通知发送线程
		addRequest(pack);
		return true;
	}

	/**
	 * 发送消息
	 * 
	 * @param type
	 * @param order
	 * @param body
	 * @return
	 */
	public boolean sendMessage(int type, int order, byte[] body)
	{
		int destId = DEST_WORLD;
		byte[] pack = packageMessage(destId, type, order, body);
		// 把一个数据包放进发送队列，并通知发送线程
		addRequest(pack);
		return true;
	}

	/**
	 * 线程运行
	 */
	public void run()
	{
		try {
			while (!m_isClosing) {
				Body body = getReceive();
				if (body != null) {
					//记录当前需要处理的消息的id
					s_perseOrderID = body.m_id;
					//处理消息体
					perseBody(body.m_data);
					body.dispose();
					body = null;
					snooze(50);
				}
				
//			if (m_receives.size() > 0) {
//				//取出队列中第一个消息体
//				Body body = (Body) m_receives.elementAt(0);
//				//记录当前需要处理的消息的id
//				s_perseOrderID = body.m_id;
//				//处理消息体
//				perseBody(body.m_data);
//				//处理完后清除该消息体
//				m_receives.removeElementAt(0);
//				body.dispose();
//				continue;
//			}
//			try {
//				Thread.sleep(100);
//			}
//			catch (InterruptedException e) {
////				e.printStackTrace();
//			}
			}
		}
		catch (InterruptedException ex) {
//			ex.printStackTrace();
			Tools.debug(ex);
		}
	}

	/**
	 * 打开socket连接
	 */
	private void openSocket()
	{
		try {
			try {
				// 打开一个输入输出流连接
				m_socket = (StreamConnection) Connector.open(m_url);
			}
			catch (SecurityException e) {
				e.printStackTrace();
				m_handler.recvMessage(GameProtocol.CONNECTION_BROKEN, null);
				return;
			}
			m_is = m_socket.openDataInputStream();
			m_os = m_socket.openDataOutputStream();
		}
		catch (IOException ex) {
			ex.printStackTrace();
			m_handler.recvMessage(GameProtocol.CONNECTION_BROKEN, null);
			return;
		}
		// 标志此连接是可用的
		m_alive = true;
		// 通知handler线程创建
		m_handler.recvMessage(GameProtocol.CONNECTION_CREATED, null);
	}

	/**
	 * 读
	 */
	private void reading()
	{
		while (m_alive) {
			if (!canRead()) {
				snooze(50);
				continue;
			}
			issueRead();
		}
		if (!m_isClosing) {
			m_handler.recvMessage(GameProtocol.CONNECTION_BROKEN, null);
		}
	}

	/**
	 * 写
	 * 
	 * @throws InterruptedException
	 */
	private void sending() throws InterruptedException
	{
		while (m_alive) {
			if (!canSend()) {
				snooze(100);
				continue;
			}
			byte[] msg = getRequest();
			if (msg != null) {
				issueWrite(msg);
				msg = null;
				snooze(50);
			}
		}
		if (!m_isClosing) {
			m_handler.recvMessage(GameProtocol.CONNECTION_BROKEN, null);
		}
	}

	/**
	 * 处理读异常
	 * 
	 * @param e
	 */
	private void stopReadForException(Exception e)
	{
		m_alive = false;
		if (m_handler != null) {
			m_handler.recvMessage(GameProtocol.CONNECTION_MESSAGE, null);
		}
	}

	private boolean canRead()
	{
		try {
			int num = m_is.available();
			if (num <= 0) {
				return false;
			}
			return true;
		}
		catch (IOException ex) {
			Tools.debug(ex);
			stopReadForException(ex);
			return false;
		}
		catch (NullPointerException e) {
			e.printStackTrace();
			return false;
		}
	}

	private boolean canSend()
	{
		return true;
	}

	private void issueRead()
	{
		// int len;
		try {
			// 读出包头数据
			// byte[] header = new byte[PACKAGE_RECEIVE_HEADER_LENGTH];
			// len = m_is.read(header, 0, PACKAGE_RECEIVE_HEADER_LENGTH);
			byte[] header = readInputStream(m_is, PACKAGE_RECEIVE_HEADER_LENGTH);
			// 包长度异常
			// if (len < PACKAGE_RECEIVE_HEADER_LENGTH) {
			// throw new Exception();
			// }
			// 解析包头
			if (!unpackageMessage(header)) {
				throw new Exception();
			}
			// 读出包体数据
			// byte[] body = new byte[s_bodyLength];
			// len = m_is.read(body, 0, s_bodyLength);
			// if (len < s_bodyLength) {
			// throw new Exception();
			// }
			byte[] body = readInputStream(m_is, s_bodyLength);

//			// 解析包体
//			perseBody(body);
			addReceive(new Body(s_recvOrderID, body));
//			m_receives.addElement(new Body(s_recvOrderID, body));

			body = null;
			header = null;
		}
		catch (Exception e) {
			Tools.debugPrintln("issueRead 异常 : " + e.toString());
			// e.printStackTrace();
			if (!m_isClosing) {
				stopReadForException(e);
			}
		}
	}

	private byte[] readInputStream(InputStream is, int bodyLength) throws IOException
	{
		int len = 0;// 已读取长度
		int curLen = 0;// 此次读取长度
		byte[] body = new byte[bodyLength];
		do {
			curLen = is.read(body, len, bodyLength - len);
			len += curLen;
//			Tools.debugPrintln("读取长度 ===================== " + curLen);
		}
		while (len < bodyLength);
		return body;
	}

	private void stopSendForException(Exception e)
	{
		m_alive = false;
	}

	private void issueWrite(byte[] msg)
	{
		try {
			if (msg != null) {
				m_os.write(msg);
				m_os.flush();
				m_handler.recvMessage(GameProtocol.CONNECTION_MESSAGE, null);
			}
		}
		catch (Exception e) {
			stopSendForException(e);
		}
	}

	private void snooze(int ms)
	{
		try {
			if (ms > 0) {
				Thread.sleep(ms);
			}
			Thread.yield();
		}
		catch (InterruptedException ex) {
			Tools.debug(ex);
		}
	}

	private class ReaderThread implements Runnable
	{
		ReaderThread()
		{
			new Thread(this).start();
		}

		public void run()
		{
			reading();
		}
	}

	private class WriterThread implements Runnable
	{
		WriterThread()
		{
			new Thread(this).start();
		}

		public void run()
		{
			try {
				sending();
			}
			catch (InterruptedException ex) {
			}
		}
	}
}
